package gsolver;

import gsolver.GChromosome;
import gsolver.GFirstFitModifie;

import org.apache.commons.math.genetics.MutationPolicy;
import org.apache.commons.math.genetics.Chromosome;

import java.util.List;
import java.util.ArrayList;
import java.util.Random;

/**
 * Mutation pour notre algorithme génétique.
 */
public class GMutation implements MutationPolicy {
    static final public double tauxSwap = 1/2;
    static final public double tauxRetrait = 1/2;
    private Random rand;

    public GMutation(Random rand) {
	this.rand = rand;
    }

    /**
     * Opérateur de mutation, fait au hasard:
     * - swap de deux lots côte à côte
     * - retire un lot au hasard, et réinsère ses jobs avec l'heuristique FFM.
     */
    public Chromosome mutate(Chromosome original) {
	GChromosome nouveau = (GChromosome)original;

	if (rand.nextDouble() <= tauxSwap) {
	    nouveau = swap(nouveau);
	}
	if (rand.nextDouble() <= tauxRetrait) {
	    nouveau = retireLotAleatoire(nouveau);
	}

	return nouveau;
    }

    public GChromosome swap(GChromosome original) {
	int i = rand.nextInt(original.getLength() - 2);
	int j = i + 1;
	
	List<Lot> ancien = original.getRepresentation();
	ArrayList<Lot> nouveau = new ArrayList<Lot>(ancien);

	nouveau.add(i, ancien.get(j));
	nouveau.add(j, ancien.get(i));

	return new GChromosome(nouveau);
    }

    public GChromosome retireLotAleatoire(GChromosome original) {
	int indexARetirer = rand.nextInt(original.getLength() - 1);
	Integer[] aRajouter = 
	    original.getRepresentation().get(indexARetirer).getJobs().toArray(new Integer[0]);
	ArrayList<Lot> representation = new ArrayList<Lot>(original.getLength());

	for (int i = 0; i < original.getLength(); i++) {
	    if (i != indexARetirer) {
		representation.add(original.getRepresentation().get(i));
	    }
	}

	GFirstFitModifie.insererFFM(representation, aRajouter);

	return new GChromosome(representation);
    }
}